/*
 * SFTPClient.cpp
 *
 *  Created on: Apr 10, 2011
 *      Author: sms103
 */

#include <iostream>
#include <fstream>
#include <sstream>

#include "../shared/simpledns.h"
#include "SFTPClient.h"

using namespace std;
SFTPClient::SFTPClient(const char * paramFileName) {
	paramParser = new ParamParser();
	paramParser->parseParams(paramFileName);

	setParams();
	connected = false;
	listener = new SFTPClientListener(this);
	listener->runListener();
}

void SFTPClient::setParams(){
	//set port num
	this->paramParser->setStringParam(&nsrootFile,"nsroot","");
}

bool SFTPClient::connectToServer(string hostname){
	if(connected)return false;//already connected, wont connect again.

	string ipaddr;
	//attempt to resolve the name...


	IPAddress ipAddr;

	addr_record addr;
	struct in_addr ip_addr;
	uint16_t port;
	if(resolve_from_file(nsrootFile.c_str(), hostname.c_str(), &addr) == 0)
	{
		memcpy(&ip_addr.s_addr, &addr.addr, 4);
		ipAddr.setAddrInAddr(&ip_addr);
		memcpy(&port,&addr.port,2);
	}
	else
	{
		cout << "Could not resolve name: " << hostname << "\n";
		return false;
	}

	//set up our ctrl connection
	TCPSocket *sock = new TCPSocket();

	cout << "Connecting to SFTP Server.."<<endl;
	if(!sock->tcpConnect(ipAddr,(int)port)){
		delete(sock);
		cout << "Connection failed."<<endl;
		return false;
	}

	ctrlConnection = new SFTPConnection(sock,true,paramParser);
	bool retval = ctrlConnection->init();
	if(!retval){
		delete(ctrlConnection);
		return false;
	}
	cout << "Connection established."<<endl;
	msg = new SFTPMessage(ctrlConnection->getTransportMSS());
	msg->setType(MSG_TYPE_CTRL_INIT);

	//TODO: check for timeouts here
	retval = ctrlConnection->sendMessage(msg);
	if(!retval){
		delete(msg);
		delete(ctrlConnection);
		return false;
	}
	ctrlConnection->recvMessage(msg);

	if(msg->getHeader()->type != MSG_TYPE_CTRL_INIT){
		delete(ctrlConnection);
		delete(msg);
		return false;
	}
	//get our session ID that the server returned in the ctrl init ack
	sessionID = msg->getHeader()->attr;

	//set up data connection now that ctrl is open
	sock = new TCPSocket();

	if(!sock->tcpConnect(ipAddr,port)){
		delete(sock);
		delete(ctrlConnection);
		delete(msg);
		return false;
	}
	dataConnection = new SFTPConnection(sock,true,paramParser);
	retval = dataConnection->init();
	if(!retval){
		delete(ctrlConnection);
		delete(dataConnection);
		delete(msg);
		return false;
	}

	msg->setType(MSG_TYPE_DATA_INIT);
	//msg already has our session ID set as in the attr field of header
	//TODO: check timeouts here too
	dataConnection->sendMessage(msg);

	dataConnection->recvMessage(msg);
	//get the data init ack
	if(msg->getHeader()->type != MSG_TYPE_DATA_INIT){
		delete(ctrlConnection);
		delete(dataConnection);
		delete(msg);
		return false;
	}

	connected = true;
	fileTransporter = new FileTransporter(dataConnection);
	return true;

}

void SFTPClient::disconnect(){
	if(!connected)return;
	msg->clearData();
	msg->setType(MSG_TYPE_CLOSE);
	//cout <<"Sending close message.."<<endl;
	ctrlConnection->sendMessage(msg);
	cout << "Closing connections.."<<endl;
	dataConnection->close();
	ctrlConnection->close();
	connected = false;
	cout <<"Disconnected from server."<<endl;
}


bool SFTPClient::putFile(string localFileName,string remoteFileName){
	if(!connected)return false;
	msg->clearData();
	msg->setType(MSG_TYPE_PUT);
	msg->setStrData(remoteFileName);
	ctrlConnection->sendMessage(msg);

	return fileTransporter->sendFile(localFileName);

}



bool SFTPClient::getFile(string localFileName, string remoteFileName){
	if(!connected)return false;

	msg->clearData();
	msg->setType(MSG_TYPE_GET);
	msg->setStrData(remoteFileName);
	ctrlConnection->sendMessage(msg);

	return fileTransporter->recvFile(localFileName);

}



bool SFTPClient::listRemoteDir(string remotePathName,string& contents){
	if(!connected)return false;
	cout<<"getting remote dir contents: "<<remotePathName<<endl;
	msg->clearData();
	msg->setType(MSG_TYPE_LIS);
	msg->setStrData(remotePathName);
	ctrlConnection->sendMessage(msg);

	return fileTransporter->recvDirectoryContents(contents);
}



SFTPClient::~SFTPClient() {
	// TODO Auto-generated destructor stub
}


int main(int argc, char** argv){
	SFTPClient *cli;

	//param file name is passed in
	if(argc==2)cli = new SFTPClient(argv[1]);

	else cli = new SFTPClient(DEFAULT_CLIENT_PARAM_FILE_NAME);
}


bool SFTPClient::connectToServer(string ipstr, int port){
	if(connected)return false;//already connected, wont connect again.

	IPAddress ipAddr;
	ipAddr.setAddrHostname(ipstr.c_str());

	//set up our ctrl connection
	TCPSocket *sock = new TCPSocket();

	cout << "Connecting to SFTP Server.."<<endl;
	if(!sock->tcpConnect(ipAddr,port)){
		delete(sock);
		cout << "Connection failed."<<endl;
		return false;
	}

	ctrlConnection = new SFTPConnection(sock,true,paramParser);
	bool retval = ctrlConnection->init();
	if(!retval){
		delete(ctrlConnection);
		return false;
	}
	cout << "Connection established."<<endl;
	msg = new SFTPMessage(ctrlConnection->getTransportMSS());
	msg->setType(MSG_TYPE_CTRL_INIT);

	//TODO: check for timeouts here
	retval = ctrlConnection->sendMessage(msg);
	if(!retval){
		delete(msg);
		delete(ctrlConnection);
		return false;
	}
	ctrlConnection->recvMessage(msg);

	if(msg->getHeader()->type != MSG_TYPE_CTRL_INIT){
		delete(ctrlConnection);
		delete(msg);
		return false;
	}
	//get our session ID that the server returned in the ctrl init ack
	sessionID = msg->getHeader()->attr;

	//set up data connection now that ctrl is open
	sock = new TCPSocket();

	if(!sock->tcpConnect(ipAddr,port)){
		delete(sock);
		delete(ctrlConnection);
		delete(msg);
		return false;
	}
	dataConnection = new SFTPConnection(sock,true,paramParser);
	retval = dataConnection->init();
	if(!retval){
		delete(ctrlConnection);
		delete(dataConnection);
		delete(msg);
		return false;
	}

	msg->setType(MSG_TYPE_DATA_INIT);
	//msg already has our session ID set as in the attr field of header
	//TODO: check timeouts here too
	dataConnection->sendMessage(msg);

	dataConnection->recvMessage(msg);
	//get the data init ack
	if(msg->getHeader()->type != MSG_TYPE_DATA_INIT){
		delete(ctrlConnection);
		delete(dataConnection);
		delete(msg);
		return false;
	}

	connected = true;
	fileTransporter = new FileTransporter(dataConnection);
	return true;

}
